package com.example.juc.kingdom_adventures.term10;

import org.junit.Test;

import java.util.concurrent.locks.StampedLock;

public class Client {
    private int number = 0;
    private final StampedLock lock = new StampedLock();

    /**
     * Java 代码需要考虑异常，使用 java.util.concurrent 时，
     * 获取锁之后的代码都需要放在 try 代码块中，并且需要将 unlock() 函数写在 finally 语句中，才能保证一定能够解锁
     */
    private void read() {
        long stamp = lock.tryOptimisticRead();
        int readNumber = number;
        System.out.println("乐观读取到的 number = " + readNumber);
        if (!lock.validate(stamp)) {
            try {
                stamp = lock.readLock();
                System.out.println("乐观读取到的 number " + readNumber + " 有误，换用悲观锁重新读取：number = " + number);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlockRead(stamp);
            }
        }
    }

    private void write(int change) {
        long stamp = 0;
        try {
            stamp = lock.writeLock();
            number += change;
            System.out.println("写入 " + number);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    @Test
    public void test() throws InterruptedException {
        // 开启一个线程写入 100 次 number
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                write(1);
            }
        }).start();

        // 开启一个线程读取 100 次 number
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                read();
            }
        }).start();

        // 睡眠一秒保证线程执行完成
        Thread.sleep(1000);
    }
}

